Skip to content

test(evm): migrate lib.js tx helpers from -b block to -b sync (CON-256)#3363

Open
wen-coding wants to merge 20 commits into
mainfrom
wen/fix_evm_hardhat_lib_for_autobahn
Open

test(evm): migrate lib.js tx helpers from -b block to -b sync (CON-256)#3363
wen-coding wants to merge 20 commits into
mainfrom
wen/fix_evm_hardhat_lib_for_autobahn

Conversation

@wen-coding
Copy link
Copy Markdown
Contributor

@wen-coding wen-coding commented May 1, 2026

Several helpers in contracts/test/lib.js used -b block, which subscribes to EventDataTx server-side. Under Autobahn the executeBlock path doesn't fire those events, so -b block deterministically times out at 60s. Sei's vendored cosmos-sdk already advises against it (sei-cosmos/client/broadcast.go: "use BroadcastTxAsync or BroadcastTxSync instead").

Migrated to -b sync (with new waitForBlocks(blocks=2) helper between submissions):

  • evmSend, bankSend, fundSeiAddress, associateKey, passProposal vote — callers don't need the deliver_tx response.
  • createTokenFactoryTokenAndMint — derives the denom locally as factory/<creator>/<subdenom> instead of reading the create_denom event.
  • proposeParamChange — polls maxProposalId() and asserts the new proposal's title matches what we submitted (catches concurrent submission / DeliverTx silent failure).
  • EVMPrecompileTest.js Gov before-hook — replaced an inline seid tx ... -b block with the lib.js helper; reads the spec from param_change_proposal.json directly.

Verification

Test set main this PR
CometBFT precompile (6) 17s 15s
CometBFT trace (3) 16s 6s
Autobahn precompile (6) hangs at before all 10s
Autobahn trace balance diff hangs at 10s 885ms

Also unblocked under Autobahn: EVMPrecompileTest Gov (10/11 passing — Wasm out of scope), ERC20toNativePointerTest (14/14 in 17s), EVMCompatabilityTest param-change test (47s, was timing out at 120s).


Note

Medium Risk
Moderate risk because it changes how integration tests submit and observe on-chain transactions (broadcast mode, timing/polling), which could introduce new race conditions or longer waits if block production differs in CI.

Overview
Moves multiple contracts/test/lib.js CLI tx helpers from -b block to -b sync, adding waitForBlocks() to explicitly wait for chain progress after submits instead of relying on deliver-tx/event subscriptions.

Hardens higher-level helpers: createTokenFactoryTokenAndMint() now derives the tokenfactory denom deterministically and checks JSON code errors; proposeParamChange() now discovers the new proposal by polling gov state (maxProposalId() + title match) rather than parsing submit events; passProposal() votes via -b sync.

Updates EVMPrecompileTest.js to use the shared proposeParamChange() helper (loading param_change_proposal.json) instead of inlining a seid tx gov submit-proposal ... -b block call.

Reviewed by Cursor Bugbot for commit fd84af4. Bugbot is set up for automated code reviews on this repo. Configure here.

bankSend, fundSeiAddress, executeWasm, associateWasm all used -b block
(broadcast-mode block), which subscribes to tendermint's EventDataTx
for the submitted hash and waits up to 60s for it to fire. Under
Autobahn the executeBlock path doesn't invoke FireEvents, so EventDataTx
is never published and -b block hangs to the timeout, blocking every
test that funds an account or runs a wasm message in beforeEach /
before-all hooks.

Switch to -b sync (returns on mempool acceptance) plus a fixed 2s sleep
to let inclusion happen. Portable across both engines: under CometBFT
this is slightly slower than the event-driven detection -b block had,
but the difference is in the noise of the surrounding hardhat-ethers
polling. Under Autobahn it unblocks the test paths entirely.

Verified locally: EVMPrecompileTest's Bank, Addr, Distribution, Staking,
Oracle precompile sections (which depend on getAdmin → fundSeiAddress)
go from 0/all hung in before-all to 9/9 passing. Gov + Wasm precompile
sections still fail because they have direct -b block calls inside the
test files themselves; those need separate substitutions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).

BuildFormatLintBreakingUpdated (UTC)
✅ passed✅ passed✅ passed✅ passedMay 13, 2026, 10:36 PM

@wen-coding wen-coding changed the title test(evm): use -b sync + sleep in lib.js cosmos-tx helpers for Autobahn test(evm): use -b sync + sleep in lib.js cosmos-tx helpers for Autobahn (CON-257) May 1, 2026
@wen-coding wen-coding marked this pull request as draft May 1, 2026 19:18
wen-coding and others added 3 commits May 1, 2026 13:38
Same migration as the prior commit, extended to two more sites that
don't read post-execution event data:

- associateKey: result is unused (wrapped in try/catch swallowing all
  errors). The -b block timeout was a 60s wait under Autobahn before
  the catch fired.
- passProposal gov vote: caller polls proposal status afterward; the
  vote-tx return value is unused.

Helpers that parse post-execution events from the response (storeWasm,
proposeParamChange, registerPointerForERC*, etc.) stay on -b block in
this PR — they need a separate "submit then poll for tx result" change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI on this PR caught a regression: CW1155toERC1155PointerTest's "should
not transfer an NFT if not owned" reads res.code from executeWasm and
expects it to be non-zero (the wasm execution should fail when the
sender doesn't own the tokens). Under -b block, res.code is the
DeliverTx code (post-execution); under -b sync it's the CheckTx code
(mempool acceptance). For a tx that passes basic checks but fails in
DeliverTx, -b sync returns 0 and the test wrongly thinks the tx
succeeded.

executeWasm and associateWasm have callers that read post-execution
fields (code, events, logs) from the response, so they can't migrate
to the -b sync pattern without also adding a "submit then poll for tx
result" step. Revert these two; leave the truly response-agnostic
helpers (bankSend, fundSeiAddress, associateKey, passProposal vote)
on -b sync. The complex helpers are deferred to the same follow-up
PR that addresses storeWasm, proposeParamChange, and the other
event-parsing callers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@wen-coding wen-coding changed the title test(evm): use -b sync + sleep in lib.js cosmos-tx helpers for Autobahn (CON-257) test(evm): migrate response-agnostic lib.js helpers off -b block May 1, 2026
@wen-coding wen-coding changed the title test(evm): migrate response-agnostic lib.js helpers off -b block test(evm): migrate response-agnostic lib.js helpers off -b block (CON-257) May 1, 2026
wen-coding and others added 2 commits May 1, 2026 14:23
Reviewer flagged the magic 2s sleep after -b sync submissions: under
CometBFT (block ~1s) it's marginal; under Autobahn (block ~100ms) it's
20x longer than needed. Both are arbitrary.

Replace with waitForBlocks(1): poll eth_blockNumber every 50ms until
the chain advances by one block, with a 15s timeout. Engine-agnostic
substitute that returns as soon as the next block lands.

Net wall-clock impact (Bank/Addr/Distribution precompile sections):
- CometBFT: 19s → 15s
- Autobahn: 39s → 10s

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI on this PR caught a sequence mismatch in SeiSoloTest's
"Claim CW20 Tester / before all": fundSeiAddress submits with -b sync
and waitForBlocks(1) returns when the next block lands. That next
block can be empty (the submitted tx is still in mempool and lands
one block later), so the chain hasn't advanced the funder's account
sequence yet. The follow-up storeWasm queries the funder's account,
gets the stale sequence, signs with it, and is rejected when the
funder tx finally lands a block later and bumps the sequence.

Default to 2 blocks instead of 1: closes the empty-next-block race
without reintroducing a fixed sleep. Callers no longer pass an
explicit block count — the helper takes care of the safety margin.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@wen-coding wen-coding changed the title test(evm): migrate response-agnostic lib.js helpers off -b block (CON-257) test(evm): migrate response-agnostic lib.js helpers off -b block (CON-256) May 3, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.13%. Comparing base (7ad44fb) to head (fd84af4).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #3363      +/-   ##
==========================================
- Coverage   59.27%   59.13%   -0.14%     
==========================================
  Files        2114     2097      -17     
  Lines      175221   171838    -3383     
==========================================
- Hits       103864   101622    -2242     
+ Misses      62311    61399     -912     
+ Partials     9046     8817     -229     
Flag Coverage Δ
sei-db 70.41% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.
see 131 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

wen-coding and others added 4 commits May 4, 2026 10:43
Two more lib.js helpers were still using --broadcast-mode=block. Under
Autobahn the executeBlock path doesn't fire EventDataTx, so -b block
hangs to its 60s timeout on every call.

evmSend (used by fundAddress, called from setupSigners and many test
file before-hooks): convert to -b sync + waitForBlocks. Callers read
only the txhash from the output, which is present in either format,
so no other adjustment needed. This unblocks EVMPrecompileTest and
EVMGigaTest's `transfer to non-existent contract with data` (latter
verified passing in 126ms after the fix).

proposeParamChange: convert to -b sync. The tx response under -b sync
no longer carries deliver_tx events, so we can't read proposal_id from
the submit_proposal event. Poll gov state instead (max-id-before vs
max-id-after) — autobahn doesn't run a Cosmos-side tx indexer so
seid q tx <hash> isn't an option. New maxProposalId helper handles the
"no proposals exist yet" case explicitly via try/catch; using a shell
`|| echo '{...}'` fallback breaks because the docker-exec wrapper
double-quotes the inner command. Verified by EVMCompatabilityTest
test #3 (`should reproduce mismatch by changing param`) passing in
47s after the fix (was timing out at 120s with -b block).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Last lib.js helper still using --broadcast-mode=block. Same Autobahn
incompatibility as evmSend / proposeParamChange: executeBlock doesn't
fire EventDataTx, so -b block hangs to its 60s timeout on every call,
which blocked ERC20toNativePointerTest's before-all hook.

The original code read the new denom from the create_denom event in
the tx response. Under -b sync we don't get deliver_tx events, but
the tokenfactory denom is deterministic — `factory/<creator>/<subdenom>`
where creator is the bech32 of the --from key. Construct it locally
from getKeySeiAddress instead.

Verified: ERC20toNativePointerTest passes 14/14 in 17s after the fix
(previously 0/1, hung 60s+ on the before-all hook).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gov Precompile section's before-hook had its own inline
'seid tx gov submit-proposal param-change ... -b block' which hangs
60s under Autobahn. Replace with the lib.js proposeParamChange helper
(now -b sync + poll gov state).

EVMPrecompileTest goes from 9/11 to 10/11 — only the Wasm Precompile
section still fails (out of scope; wasm being decommed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
wen-coding added a commit that referenced this pull request May 7, 2026
…y scripts

Builds on the previous commit (submitAndWaitForTx + storeWasm +
registerPointerForERC20 worked examples) and finishes the response-
reading-helper migration that #3363 deferred.

Migrated in contracts/test/lib.js:
  - storeWasm                       (already done in prior commit)
  - registerPointerForERC20         (already done in prior commit)
  - registerPointerForERC721        NEW
  - registerPointerForERC1155       NEW
  - executeWasm                     NEW (the one #3363 had to revert)
  - associateWasm                   NEW
  - proposeCW20toERC20Upgrade       NEW
  - instantiateWasm                 NEW
  - deployErc20PointerForCw20       NEW (-b block -> -b sync; existing EVM-receipt poll handles wait)
  - deployErc20PointerNative        NEW (same)
  - deployErc721PointerForCw721     NEW (same)
  - deployErc1155PointerForCw1155   NEW (same)

New shared bash helper: integration_test/contracts/_tx_helpers.sh
  Defines submit_and_wait_for_tx() — bash equivalent of the JS helper.
  Reads the broadcast response from stdin (must use --broadcast-mode=sync),
  polls `seid query tx <hash>` until included, prints the tx response.

Migrated deploy scripts in integration_test/contracts/:
  - deploy_wasm_contracts.sh        (3 store + 3 instantiate calls)
  - create_tokenfactory_denoms.sh   (3 create-denom calls)
  - deploy_dex_contract.sh          (store + instantiate + register-contract + 4 register-pairs)
  - deploy_timelocked_token_contract.sh
                                    (7 bank-sends + 2 store + 2 instantiate)

Out of scope (separate effort):
  - yaml-based cosmos integration tests (gov, oracle, authz, staking,
    bank, distribution, mint) — these use -b block in shell commands
    parsed by integration_test/scripts/runner.py. Migrating needs
    runner.py support for the submit-then-poll pattern.
  - Helpers already migrated in #3363 (evmSend, bankSend, fundSeiAddress,
    associateKey, createTokenFactoryTokenAndMint, proposeParamChange,
    passProposal vote) — left unchanged here to avoid conflicts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
wen-coding and others added 6 commits May 7, 2026 12:55
Strip comments that described the old -b block behavior or contrasted
-b sync against it. Reader of the current code doesn't need to know
what was replaced; comments now describe pure invariants
(empty-next-block race, deterministic denom format, diff-against-snapshot
proposal identification, seid's empty-gov-set exit code).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Read title/description/changes/is_expedited from the JSON file directly
rather than duplicating them inline. deposit/fees stay inline (they're
not part of the proposal spec; they're CLI-level args).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…aramChange

After polling identifies the new proposal id, fetch the proposal and
assert its title matches what we submitted. Closes the sharp edge where
a concurrent submission (or DeliverTx silent failure followed by an
unrelated submission) would otherwise cause us to return someone else's
id.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Keep original command/mint_command/send_command variable names and
inline-execute pattern. Only changes vs main are: derive token_denom
locally instead of from the create_denom event, swap -b block for
-b sync, and waitForBlocks between submissions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@wen-coding wen-coding changed the title test(evm): migrate response-agnostic lib.js helpers off -b block (CON-256) test(evm): migrate lib.js tx helpers from -b block to -b sync (CON-256) May 13, 2026
@wen-coding wen-coding marked this pull request as ready for review May 13, 2026 03:00
Comment thread contracts/test/lib.js Outdated
Comment thread contracts/test/lib.js
- createTokenFactoryTokenAndMint: check response.code on each sync
  submit; previously a CheckTx rejection would silently leave the
  function with a non-existent denom. Now matches proposeParamChange's
  pattern.
- Drop redundant `await delay()` after helpers that already do
  waitForBlocks internally (fundAddress, getNativeAccount, setupSigners
  loop). The delay was carrying inclusion-wait duties; waitForBlocks
  inside the helper supersedes it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d5196a6. Configure here.

Comment thread contracts/test/lib.js
If multiple proposals land in one polling interval (250ms), the loop
must scan every id in (maxIdBefore, cur] to find ours by title — not
just the max. Otherwise we'd throw on a title mismatch against a
concurrent submission's proposal even when ours did land.

Also keep polling (rather than erroring) if none of the new ids match
our title; the 30s deadline catches the genuine "ours never landed"
case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant